package com.own.component.security.aspect;

import com.own.aop.permission.PermissionRole;
import com.own.aop.permission.PermissionRoleExcept;
import com.own.aop.permission.PermissionRoles;
import com.own.aop.permission.PermissionRolesExcept;
import com.own.component.common.exception.BusinessException;
import com.own.component.common.login.util.SessionUserUtil;
import com.own.component.security.condition.RoleAspectCondition;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * PermissionRoleAspect
 *
 * @author chenxueli
 * @date 2022-08-09 14:54:00
 */
@Aspect
@Component
@Order(1)
@Conditional(RoleAspectCondition.class)
public class PermissionRoleAspect {

    @Pointcut("@annotation(com.own.aop.permission.PermissionRole)")
    public void role() {
    }

    @Pointcut("@annotation(com.own.aop.permission.PermissionRoles)")
    public void roles() {
    }

    @Pointcut("@annotation(com.own.aop.permission.PermissionRoleExcept)")
    public void roleExcept() {
    }

    @Pointcut("@annotation(com.own.aop.permission.PermissionRolesExcept)")
    public void roleExcepts() {
    }

    @Before("role() && @annotation(data)")
    public void roleBefore(JoinPoint point, PermissionRole data) {
        check(Collections.singletonList(data.value()), true);
    }

    @Before("roles() && @annotation(data)")
    public void rolesBefore(JoinPoint point, PermissionRoles data) {
        var array = Arrays.stream(data.value()).map(PermissionRole::value).toList();
        check(array, true);
    }

    @Before("roleExcept() && @annotation(data)")
    public void roleExceptBefore(JoinPoint point, PermissionRoleExcept data) {
        check(Collections.singletonList(data.value()), false);
    }

    @Before("roleExcepts() && @annotation(data)")
    public void roleExceptsBefore(JoinPoint point, PermissionRolesExcept data) {
        var array = Arrays.stream(data.value()).map(PermissionRoleExcept::value).toList();
        check(array, false);
    }

    /**
     * 判断方法
     *
     * @param roleList 角色名称列表
     * @param exist    是否需要全部存在
     */
    private void check(List<String> roleList, boolean exist) {
        // 判断当前登录用户是否有该角色信息
        var roleNameList = SessionUserUtil.getPermissionUser().roleNameList();
        if (exist) {
            // 判断所需要的列表中是否有当前用户所有的角色
            var flag = roleList.stream().anyMatch(roleNameList::contains);
            if (flag) {
                return;
            }
            throw new BusinessException("当前用户没有：{}，角色信息，无法访问", roleList.toString());
        } else {
            // 用户的角色都不能出现在判断的列表中才能访问
            var flag = roleList.stream().noneMatch(roleNameList::contains);
            if (flag) {
                return;
            }
            throw new BusinessException("当前用户有：{}，角色信息，无法访问", roleList.toString());
        }
    }

}
